package com.youlu.campus.wechat.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.wechat.pay.contrib.apache.httpclient.util.RsaCryptoUtil;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.wechat.facotrys.WechatComplaintServiceFacotry;
import com.youlu.campus.entity.ActivityInfo;
import com.youlu.campus.entity.OrderInfo;
import com.youlu.campus.entity.UserParticipateActivityInfo;
import com.youlu.campus.entity.WechatMerchantConfig;
import com.youlu.campus.entity.card.entity.CardOrder;
import com.youlu.campus.entity.complaint.ComplaintCommentInfo;
import com.youlu.campus.entity.complaint.ComplaintNotify;
import com.youlu.campus.entity.complaint.ComplaintNotifyLog;
import com.youlu.campus.entity.complaint.ComplaintOrderInfo;
import com.youlu.campus.entity.complaint.MerchantComplaint;
import com.youlu.campus.entity.complaint.NotifyDecrypt;
import com.youlu.campus.entity.complaint.ReplyUserComplaint;
import com.youlu.campus.entity.complaint.vo.ComplaintHistoryDetailResult;
import com.youlu.campus.entity.complaint.vo.ComplaintHistoryResult;
import com.youlu.campus.entity.complaint.vo.ExportComplaintVO;
import com.youlu.campus.entity.complaint.vo.MerchantInfoVO;
import com.youlu.campus.entity.complaint.vo.QueryComplaintVO;
import com.youlu.campus.entity.complaint.vo.ReplyComplaint;
import com.youlu.campus.entity.course.UserCourseOrder;
import com.youlu.campus.service.activity.UserParticipateActivityInfoService;
import com.youlu.campus.service.cache.CacheActivityService;
import com.youlu.campus.service.order.OrderService;
import com.youlu.campus.service.wechat.WechatMerchantConfigService;
import com.youlu.campus.wechat.service.WechatComplaintService;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.BadPaddingException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * 商户号投诉处理
 * 注意流量探测包：WECHATPAY/SIGNTEST/
 */
@Slf4j
@Service
public class MerchantComplaintService {

    @Autowired
    private WechatComplaintServiceFacotry facotry;

    @Resource
    private MongoTemplate mongoTemplate;

    @Autowired
    private CacheActivityService activityService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private UserParticipateActivityInfoService userParticipateActivityInfoService;

    @Autowired
    private WechatMerchantConfigService wechatMerchantConfigService;

    @Value("${sys.pay.wx.bizDomain}")
    private String bizDomain;

    public List<ComplaintCommentInfo> commentDetailByComplaintId(String complaintId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("complaintId").is(complaintId));
        query.with(Sort.by(Sort.Direction.DESC, "createdTime"));
        return this.mongoTemplate.find(query, ComplaintCommentInfo.class);
    }

    public void commentSave(ComplaintCommentInfo complaintCommentInfo) {
        complaintCommentInfo.setCreatedTime(new Date());
        this.mongoTemplate.save(complaintCommentInfo);
    }


    public void batchProcessed(QueryComplaintVO batchComplaint) {
        if (CollectionUtils.isEmpty(batchComplaint.getComplainIdList())) {
            log.error("批量审核投诉处理完成投诉ID不能为空");
            return;
        }
        String currentUserId = batchComplaint.getCurrentUserId();
        log.info("【批量处理投诉已完成】处理人->{} 投诉内容处理->{}  start", batchComplaint.getCurrentUserId(),
                JSON.toJSONString(batchComplaint.getComplainIdList()));
        batchComplaint.getComplainIdList().parallelStream().forEach(complainId -> {
            completeComplaint(complainId, currentUserId);
        });
        log.info("【批量处理投诉已完成】处理人->{} 处理已结束", batchComplaint.getCurrentUserId());
    }


    public Long queryComplaintPending() {
        Query query = new Query();
        query.addCriteria(Criteria.where("complaintState").is(MerchantComplaint.COMPLAINT_PENDING));
        return this.mongoTemplate.count(query, MerchantComplaint.class);
    }


    public void export(QueryComplaintVO queryComplaintVO, HttpServletResponse response) throws UnsupportedEncodingException {
        Query query = getQuery(queryComplaintVO);
        query.with(Sort.by(Sort.Direction.DESC, "complaintTime"));
        query.limit(5000);
        List<MerchantComplaint> list = this.mongoTemplate.find(query, MerchantComplaint.class);
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        log.info("用户->{}操作导出商户投诉通知数据", queryComplaintVO.getCurrentUserId());
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = "商户投诉" + System.currentTimeMillis();
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        List<ExportComplaintVO> exportList = list.stream().map(merchantComplaint -> {
            ExportComplaintVO exportComplaint = new ExportComplaintVO();
            exportComplaint.setComplaintId(merchantComplaint.getComplaintId());
            if (merchantComplaint.getIncomingUserResponse()) {
                exportComplaint.setIncomingUserResponse("用户有留言");
            }
            exportComplaint.setUserComplaintTimes(merchantComplaint.getUserComplaintTimes());
            exportComplaint.setMerchantName(merchantComplaint.getMerchantName());
            exportComplaint.setComplaintTime(DateUtil.format(merchantComplaint.getComplaintTime(), "yyyy-MM-dd " +
                    "HH:mm:ss"));
            exportComplaint.setComplaintDetail(merchantComplaint.getComplaintDetail());
            exportComplaint.setPayerPhone(merchantComplaint.getPayerPhone());
            if (MerchantComplaint.COMPLAINT_PENDING.equals(merchantComplaint.getComplaintState())) {
                exportComplaint.setComplaintState("待处理");
            } else if (MerchantComplaint.COMPLAINT_PROCESSING.equals(merchantComplaint.getComplaintState())) {
                exportComplaint.setComplaintState("处理中");
            } else {
                exportComplaint.setComplaintState("已处理完成");
            }
            List<ReplyUserComplaint> replyUserComplaintList = merchantComplaint.getReplyUserComplaintList();
            if (CollectionUtils.isNotEmpty(replyUserComplaintList)) {
                String operator = replyUserComplaintList.stream().filter(replyUserComplaint -> StringUtils.isNotBlank(replyUserComplaint.getOperatorName())).map(ReplyUserComplaint::getOperatorName).collect(Collectors.toSet()).stream().collect(Collectors.joining(","));
                exportComplaint.setOperator(operator);
            }
            List<ComplaintOrderInfo> complaintOrderInfo = merchantComplaint.getComplaintOrderInfo();
            if (CollectionUtils.isNotEmpty(complaintOrderInfo)) {
                ComplaintOrderInfo complaintOrderInfo1 = complaintOrderInfo.get(0);
                String orderNo = complaintOrderInfo1.getOutTradeNo();
                ComplaintOrderDTO dto = getComplaintOrderByOrderNo(orderNo);
                if (Objects.nonNull(dto)) {
                    exportComplaint.setActivityName(dto.getActivityName());
                    exportComplaint.setUserName(dto.getName());
                    exportComplaint.setMobile(dto.getMobile());
                    exportComplaint.setRefund(dto.getStatus());
                }
                exportComplaint.setAmount(new BigDecimal(complaintOrderInfo1.getAmount()).divide(new BigDecimal(100),
                        2, BigDecimal.ROUND_HALF_UP).toString());
                exportComplaint.setOutTradeNo(complaintOrderInfo1.getOutTradeNo());
                List<ComplaintCommentInfo> complaintCommentInfoList = commentDetailByComplaintId(merchantComplaint.getComplaintId());
                if (CollectionUtils.isNotEmpty(complaintCommentInfoList)) {
                    StringBuilder sb = new StringBuilder("");
                    complaintCommentInfoList.stream().forEach(complaintCommentInfo -> {
                        if (sb.length() > 0) {
                            sb.append(String.valueOf((char) 10));
                        }
                        sb.append(complaintCommentInfo.getComment());
                    });
                    exportComplaint.setCommentInfo(sb.toString());
                }
            }

            return exportComplaint;
        }).collect(Collectors.toList());
        try {
            EasyExcel.write(response.getOutputStream(), ExportComplaintVO.class).sheet().doWrite(exportList);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
//            try {
//                response.getOutputStream().close();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
        }
    }

    /**
     * 查看投诉历史
     *
     * @param queryComplaint
     * @return
     */
    public Page<ComplaintHistoryDetailResult> history(QueryComplaintVO queryComplaint) {
        Query query = new Query();
        query.addCriteria(Criteria.where("complaintId").is(queryComplaint.getComplaintId()));
        MerchantComplaint merchantComplaint = this.mongoTemplate.findOne(query, MerchantComplaint.class);
        if (Objects.isNull(merchantComplaint)) {
            throw new BusinessException("未查询到信息");
        }
        PageRequest pageRequest = PageRequest.of(queryComplaint.getPageNo() - 1, queryComplaint.getPageSize());
        WechatMerchantConfig wechatMerchantConfig = wechatMerchantConfigService.findByMerchantIdAndDecrypt(merchantComplaint.getMerchantId());
        //请求URL

        WechatComplaintService wechatComplaintService = facotry.getWechatComplaintService(wechatMerchantConfig);

        ComplaintHistoryResult complaintHistoryResult = wechatComplaintService.negotiationHistorys(queryComplaint.getComplaintId(), queryComplaint.getPageSize(), (queryComplaint.getPageNo() - 1));
        if (CollectionUtils.isEmpty(complaintHistoryResult.getData())) {
            return PageableExecutionUtils.getPage(new ArrayList<>(), pageRequest, () -> 0L);
        }
        return PageableExecutionUtils.getPage(complaintHistoryResult.getData(), pageRequest, () -> complaintHistoryResult.getTotal_count());
    }

    public MerchantComplaint detail(String complaintId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("complaintId").is(complaintId));
        MerchantComplaint merchantComplaint = this.mongoTemplate.findOne(query, MerchantComplaint.class);
        if (Objects.isNull(merchantComplaint)) {
            throw new BusinessException("未查询到信息");
        }
        List<ComplaintOrderInfo> complaintOrderInfo = merchantComplaint.getComplaintOrderInfo();
        if (CollectionUtils.isNotEmpty(complaintOrderInfo)) {
            String orderNo = complaintOrderInfo.get(0).getOutTradeNo();
            merchantComplaint.setOutTradeNo(orderNo);
            String refundStatus = getRefundByOrderNo(orderNo);
            merchantComplaint.setAmount(complaintOrderInfo.get(0).getAmount());
            merchantComplaint.setRefundStatus(refundStatus);
            merchantComplaint.setTransactionId(complaintOrderInfo.get(0).getTransactionId());
        }
        return merchantComplaint;
    }

    /**
     * 完成投诉 反馈处理完成
     *
     * @param complaintId
     * @param operator
     */
    public void completeComplaint(String complaintId, String operator) {
        log.info("业务员->{}操作投诉->{}已完成", operator, complaintId);
        Query query = new Query();
        query.addCriteria(Criteria.where("complaintId").is(complaintId));
        MerchantComplaint merchantComplaint = this.mongoTemplate.findOne(query, MerchantComplaint.class);
        if (Objects.isNull(merchantComplaint)) {
            return;
        }
        if (!MerchantComplaint.COMPLAINT_PROCESSING.equals(merchantComplaint.getComplaintState())) {
            throw new BusinessException("处理中投诉才能操作处理完成");
        }
        if (MerchantComplaint.COMPLAINT_PROCESSED.equals(merchantComplaint.getComplaintState())) {
            throw new BusinessException("投诉已经处理完成,请勿重复处理");
        }
        merchantComplaint.setComplaintState(MerchantComplaint.COMPLAINT_PROCESSED);
        merchantComplaint.setUpdatedTime(new Date());
        this.mongoTemplate.save(merchantComplaint);
        WechatMerchantConfig wechatMerchantConfig = wechatMerchantConfigService.findByMerchantIdAndDecrypt(merchantComplaint.getMerchantId());
        try {
            log.info("开始处理商户->{}投诉ID - >{} 标记已完成", wechatMerchantConfig.getMerchantName(), complaintId);
            WechatComplaintService wechatComplaintService = facotry.getWechatComplaintService(wechatMerchantConfig);
            wechatComplaintService.complete(complaintId);
        } catch (Exception e) {
            log.error("completeComplaint error:{}", e.getMessage(), e);
        }
    }

    public Boolean existWithMobile(String mobile) {
        Query query = new Query();
        query.addCriteria(Criteria.where("payerPhone").is(mobile));
        return mongoTemplate.exists(query, MerchantComplaint.class);

    }

    private Query getQuery(QueryComplaintVO queryComplaintVO) {
        String complaintId = queryComplaintVO.getComplaintId();
        String merchantId = queryComplaintVO.getMerchantId();
        String complaintState = queryComplaintVO.getComplaintState();
        String outTradeNo = queryComplaintVO.getOutTradeNo();
        Query query = new Query();
        if (StringUtils.isNotBlank(merchantId)) {
            query.addCriteria(Criteria.where("merchantId").is(merchantId));
        }
        if (StringUtils.isNotBlank(complaintId)) {
            query.addCriteria(Criteria.where("complaintId").is(complaintId));
        }
        if (StringUtils.isNotBlank(complaintState)) {
            query.addCriteria(Criteria.where("complaintState").is(complaintState));
        }
        if (StringUtils.isNotBlank(outTradeNo)) {
            query.addCriteria(Criteria.where("complaintOrderInfo").elemMatch(Criteria.where("outTradeNo").is(outTradeNo)));
        }
        Date startComplaintTime = queryComplaintVO.getStartComplaintTime();
        Date endComplaintTime = queryComplaintVO.getEndComplaintTime();
        if (Objects.nonNull(startComplaintTime) && Objects.nonNull(endComplaintTime)) {
            query.addCriteria(Criteria.where("complaintTime").gte(startComplaintTime).lte(endComplaintTime));
        }
        query.addCriteria(Criteria.where("deleted").ne(Boolean.TRUE));
        return query;
    }

    private ComplaintOrderDTO getComplaintOrderByOrderNo(String orderNo) {
        ComplaintOrderDTO complaintOrder = new ComplaintOrderDTO();
        Query query = new Query();
        query.addCriteria(Criteria.where("orderNo").is(orderNo));
        if (StringUtils.startsWith(orderNo, "WXLTKCSP")) {//视频订单
            UserCourseOrder userOrder = this.mongoTemplate.findOne(query, UserCourseOrder.class);
            if (Objects.nonNull(userOrder)) {
                complaintOrder.setMobile(userOrder.getPhone());
                UserParticipateActivityInfo user = userParticipateActivityInfoService.findByUserIdActivityId(userOrder.getUserId(), userOrder.getActivityId());
                if (Objects.nonNull(user)) {
                    complaintOrder.setName(user.getName());
                    if (StringUtils.isBlank(complaintOrder.getMobile())) {
                        complaintOrder.setMobile(user.getMobile());
                    }
                }
                ActivityInfo activityInfo = activityService.findById(userOrder.getActivityId());
                if (Objects.nonNull(activityInfo)) {
                    complaintOrder.setActivityName(activityInfo.getName());
                }
                Integer status = userOrder.getStatus();
                if (status == 3) {
                    complaintOrder.setStatus("退款中");
                }
                if (status == 4) {
                    complaintOrder.setStatus("已退款");
                }
            }
        } else if (StringUtils.startsWith(orderNo, "CARD")) {
            CardOrder cardOrder = this.mongoTemplate.findOne(query, CardOrder.class);
            if (Objects.nonNull(cardOrder)) {
                complaintOrder.setMobile(cardOrder.getPhone());
                complaintOrder.setName(cardOrder.getName());
                complaintOrder.setActivityName(cardOrder.getName());
                Integer status = cardOrder.getStatus();
                if (status == 3) {
                    complaintOrder.setStatus("已退款");
                }
                if (status == 4) {
                    complaintOrder.setStatus("退款中");
                }
            }
        } else {
            OrderInfo order = orderService.findByOrderNo(orderNo);//H5小程序纸质订单
            if (Objects.nonNull(order)) {
                complaintOrder.setMobile(order.getSignUpMobile());
                complaintOrder.setName(order.getSignUpName());
                ActivityInfo activityInfo = activityService.findById(order.getActivityId());
                if (Objects.nonNull(activityInfo)) {
                    complaintOrder.setActivityName(activityInfo.getName());
                }
                if (Objects.nonNull(order.getRefundType()) && order.getRefundType() == 0 && "3".equals(order.getRefundStatus())) {
                    complaintOrder.setStatus("全部退款");
                }
                if (Objects.nonNull(order.getRefundType()) && order.getRefundType() == 1 && "3".equals(order.getRefundStatus())) {
                    complaintOrder.setStatus("部分退款");
                }
                if (Objects.nonNull(order.getRefundType()) && order.getRefundType() == 1 && "6".equals(order.getStatus())) {
                    complaintOrder.setStatus("部分退款");
                }
                if (Objects.nonNull(order.getRefundType()) && order.getRefundType() == 0 && "6".equals(order.getStatus())) {
                    complaintOrder.setStatus("全部退款");
                } else {
                    complaintOrder.setStatus("未退款");
                }
            }
        }
        return complaintOrder;

    }


    public Page<MerchantComplaint> list(QueryComplaintVO queryComplaintVO) {
        Query query = getQuery(queryComplaintVO);
        long count = this.mongoTemplate.count(query, MerchantComplaint.class);
        PageRequest pageRequest = PageRequest.of(queryComplaintVO.getPageNo() - 1, queryComplaintVO.getPageSize());
        if (count == 0) {
            return PageableExecutionUtils.getPage(new ArrayList<>(), pageRequest, () -> count);
        }
//        query.with(new Sort(Sort.Direction.DESC, "complaintTime"));
        Sort sort = Sort.by(Sort.Direction.DESC, "complaintTime");
        query.with(sort);
        query.with(pageRequest);
        List<MerchantComplaint> list = this.mongoTemplate.find(query, MerchantComplaint.class);
        list.stream().map(merchantComplaint -> {
            List<ComplaintOrderInfo> complaintOrderInfo = merchantComplaint.getComplaintOrderInfo();
            if (CollectionUtils.isNotEmpty(complaintOrderInfo)) {
                String orderNo = complaintOrderInfo.get(0).getOutTradeNo();
                ComplaintOrderDTO dto = getComplaintOrderByOrderNo(orderNo);
                if (Objects.nonNull(dto)) {
                    merchantComplaint.setActivityName(dto.getActivityName());
                    merchantComplaint.setRefundStatus(dto.getStatus());
                }
                merchantComplaint.setOutTradeNo(orderNo);
//                 String refundStatus = getRefundByOrderNo(orderNo);
//                 merchantComplaint.setRefundStatus(refundStatus);
                merchantComplaint.setAmount(complaintOrderInfo.get(0).getAmount());
                merchantComplaint.setTransactionId(complaintOrderInfo.get(0).getTransactionId());
            }
            List<ComplaintCommentInfo> commentInfoList = commentDetailByComplaintId(merchantComplaint.getComplaintId());
            if (CollectionUtils.isNotEmpty(commentInfoList)) {
                merchantComplaint.setComment(commentInfoList.get(0).getComment());
            }
            return merchantComplaint;
        }).collect(Collectors.toList());
        return PageableExecutionUtils.getPage(list, pageRequest, () -> count);
    }

    public List<MerchantInfoVO> findMerchantList() {
        Query query = new Query();
        query.addCriteria(Criteria.where("deleted").ne(Boolean.TRUE));
        List<WechatMerchantConfig> list = this.mongoTemplate.find(query, WechatMerchantConfig.class);
        return list.stream().map(wechatMerchantConfig -> {
            MerchantInfoVO merchantInfo = new MerchantInfoVO();
            merchantInfo.setMerchantId(wechatMerchantConfig.getMerchantId());
            merchantInfo.setMerchantName(wechatMerchantConfig.getMerchantName());
            return merchantInfo;
        }).collect(Collectors.toList());
    }


    /**
     *  投诉- 回复用户
     *
     * @param replyComplaint
     */
    public void reply(ReplyComplaint replyComplaint) {
        String complaintId = replyComplaint.getComplaintId();
        String replyContent = replyComplaint.getReplyContent();
        if (StringUtils.isBlank(complaintId) || StringUtils.isBlank(replyContent)) {
            log.error("投诉id 回复内容为空");
            throw new BusinessException("提交回复内容不能为空");
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("complaintId").is(complaintId));
        MerchantComplaint merchantComplaint = this.mongoTemplate.findOne(query, MerchantComplaint.class);
        if (Objects.isNull(merchantComplaint)) {
            log.error("根据投诉ID ->{} 未查询到相关信息", complaintId);
            throw new BusinessException("投诉信息不存在");
        }
        List<ReplyUserComplaint> replyUserComplaintList = merchantComplaint.getReplyUserComplaintList();
        if (CollectionUtils.isEmpty(replyUserComplaintList)) {
            replyUserComplaintList = new ArrayList<>();
        }
        ReplyUserComplaint replyUserComplaint = new ReplyUserComplaint();
        replyUserComplaint.setOperationTime(new Date());
        replyUserComplaint.setOperator(replyComplaint.getReplyUserId());
        replyUserComplaint.setOperatorName(replyComplaint.getReplyUserName());
        replyUserComplaint.setResponseImages(replyComplaint.getReplyImages());
        replyUserComplaint.setResponseContent(replyComplaint.getReplyContent());
        replyUserComplaint.setJumpUrl(replyComplaint.getJumpUrl());
        replyUserComplaint.setJumpUrlText(replyComplaint.getJumpUrlText());
        replyUserComplaintList.add(replyUserComplaint);
        merchantComplaint.setReplyUserComplaintList(replyUserComplaintList);
        merchantComplaint.setComplaintState(MerchantComplaint.COMPLAINT_PROCESSING);
        this.mongoTemplate.save(merchantComplaint);
        //提交回复微信商户平台
        WechatMerchantConfig wechatMerchantConfig = wechatMerchantConfigService.findByMerchantIdAndDecrypt(merchantComplaint.getMerchantId());
        replyUserComplaint.setComplaintId(merchantComplaint.getComplaintId());
        replyUserComplaint.setComplaintedMchid(merchantComplaint.getMerchantId());
        try {
            WechatComplaintService wechatComplaintService = facotry.getWechatComplaintService(wechatMerchantConfig);
            wechatComplaintService.response(replyUserComplaint);
        } catch (Exception e) {
            log.error("reply error:{}", e.getMessage(), e);
        }

    }

    /**
     *  同步商户投诉通知地址
     *
     * @param merchantId
     * @param notifyUrl
     */
    public void doSyncNotifyUrl(String merchantId, String notifyUrl) {
        WechatMerchantConfig wechatMerchantConfig = wechatMerchantConfigService.findByMerchantIdAndDecrypt(merchantId);
        WechatComplaintService wechatComplaintService = facotry.getWechatComplaintService(wechatMerchantConfig);

        wechatComplaintService.createNotifyUrl(bizDomain + "/campus" + notifyUrl);
    }

    /**
     * 删除商户投诉通知地址
     *
     * @param merchantId
     */
    public void doDeleteNotifyUrl(String merchantId) {
        WechatMerchantConfig wechatMerchantConfig = wechatMerchantConfigService.findByMerchantIdAndDecrypt(merchantId);
        WechatComplaintService wechatComplaintService = facotry.getWechatComplaintService(wechatMerchantConfig);
        wechatComplaintService.deleteNotifyUrl();
    }

    /**
     * TODO 这个方法有问题 待确认
     */
    public void initCompare() {
        Query query = new Query();
        query.addCriteria(Criteria.where("serialNumber").is("2A3447B272E24342B34B994EE7FFCEBD9377487D"));
        List<ComplaintNotifyLog> logList = this.mongoTemplate.find(query.with(Sort.by(Sort.Direction.DESC, "id")), ComplaintNotifyLog.class);
        //TODO 看不懂这个逻辑 从数据库查出来 然后在插入一遍? 有啥意义
        logList.stream().forEach(complaintNotifyLog -> {
            Map<String, Object> result = new HashMap<>(2);
            ComplaintNotify complaintNotify = complaintNotifyLog.getComplaintNotify();
            getNotifyResultMap(complaintNotifyLog.getTimestamp(),
                    complaintNotifyLog.getNonce(),
                    complaintNotifyLog.getSignature(),
                    complaintNotifyLog.getSerialNumber(),
                    result,
                    null,
                    complaintNotify);
        });
    }

    public String doQueryNotifyUrl(String merchantId) {
        WechatMerchantConfig wechatMerchantConfig = wechatMerchantConfigService.findByMerchantIdAndDecrypt(merchantId);
        WechatComplaintService wechatComplaintService = facotry.getWechatComplaintService(wechatMerchantConfig);
        String url = wechatComplaintService.getNotifyUrl().getUrl();
        return url;
    }

    public void remoteDetail(String merchantId, String complaintId) {
        WechatMerchantConfig wechatMerchantConfig = wechatMerchantConfigService.findByMerchantIdAndDecrypt(merchantId);
        NotifyDecrypt notifyDecrypt = new NotifyDecrypt();
        notifyDecrypt.setComplaintId(complaintId);
        notifyDecrypt.setActionType("CREATE_COMPLAINT");
        getRemoteComplaintDetail(wechatMerchantConfig, notifyDecrypt, "COMPLAINT.CREATE");
    }

    public HashMap complaintlist(String merchantId, String beginDate, String endDate, Integer limit, Integer offset) {
        WechatMerchantConfig wechatMerchantConfig =wechatMerchantConfigService.findByMerchantIdAndDecrypt(merchantId);
        WechatComplaintService wechatComplaintService = facotry.getWechatComplaintService(wechatMerchantConfig);
        return wechatComplaintService.queryList(beginDate, endDate, limit, offset);
    }

    public Map<String, Object> complaintNotify2(HttpServletRequest request, String requestBody) {
        //获取请求头数据
        String signatue = request.getHeader("Wechatpay-Signature");
        String serialNo = request.getHeader("Wechatpay-Serial");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String signatureType = request.getHeader("Wechatpay-Signature-Type");
        log.info("complaintNotify signatue:  {}, serialNo:  {}, nonce:  {}, timestamp:  {}, signatureType:  {}", signatue, serialNo, nonce, timestamp, signatureType);

        Map<String, Object> result = new HashMap<>(2);
        ComplaintNotify complaintNotify = JSON.parseObject(requestBody, ComplaintNotify.class);
        complaintNotify.setType(2);
        return getNotifyResultMap(timestamp, nonce, signatue, serialNo, result, requestBody, complaintNotify);
    }

    public Map<String, Object> complaintNotify(HttpServletRequest request) {

        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String signature = request.getHeader("Wechatpay-Signature");
        String serialNumber = request.getHeader("Wechatpay-Serial");
        Map<String, Object> result = new HashMap<>(2);
        log.info("投诉通知证书序利号->{} | signature ->{}", serialNumber, signature);
        String requestBody = getRequestBody(request);
        if (StringUtils.isBlank(requestBody)) {
            log.error("merchantSerialNumber ->{} 未获取到请求体内容", serialNumber);
            result.put("code", "FAIL");
            result.put("message", "失败");
            return result;
        }
        log.info("requestBody-> {}", requestBody);
        ComplaintNotify complaintNotify = JSON.parseObject(requestBody, ComplaintNotify.class);
        complaintNotify.setType(2);
        return getNotifyResultMap(timestamp, nonce, signature, serialNumber, result, requestBody, complaintNotify);
    }

    private Map<String, Object> getNotifyResultMap(String timestamp, String nonce, String signature,
                                                   String serialNumber, Map<String, Object> result, String body, ComplaintNotify complaintNotify) {
        String eventType = complaintNotify.getEventType();
        //记录通知日志
        ComplaintNotifyLog complaintNotifyLog = new ComplaintNotifyLog();
        complaintNotifyLog.setComplaintNotify(complaintNotify);
        complaintNotifyLog.setTimestamp(timestamp);
        complaintNotifyLog.setNonce(nonce);
        complaintNotifyLog.setNotifyId(complaintNotify.getId());
        complaintNotifyLog.setSignature(signature);
        complaintNotifyLog.setSerialNumber(serialNumber);
        complaintNotifyLog.setCreatedTime(new Date());
        complaintNotifyLog.setRequestJson(JSON.toJSONString(complaintNotify));
        complaintNotifyLog.setComplaintNotify(complaintNotify);
        this.mongoTemplate.save(complaintNotifyLog);

        WechatMerchantConfig wechatMerchantConfig = wechatMerchantConfigService.findByPlatformSerialNumberAndDecrypt(serialNumber);
        if (Objects.isNull(wechatMerchantConfig)) {
            log.error("merchantSerialNumber ->{} 证书序列未找到", serialNumber);
            result.put("code", "FAIL");
            result.put("message", "失败");
            return result;
        }
        WechatComplaintService wechatComplaintService = facotry.getWechatComplaintService(wechatMerchantConfig);
        if (Objects.isNull(wechatMerchantConfig)) {
            log.error("merchantSerialNumber ->{} 证书序列未找到", serialNumber);
            result.put("code", "FAIL");
            result.put("message", "失败");
            return result;
        }
        try {
            NotifyDecrypt notifyDecrypt = wechatComplaintService.notifyParse(signature, serialNumber, nonce, timestamp, body);
            log.info("解密内容对象->{} 投诉id - > action_type - >{}", notifyDecrypt.getComplaintId(), notifyDecrypt.getActionType());
            //解密获取详情进行插入更新操作
            getRemoteComplaintDetail(wechatMerchantConfig, notifyDecrypt, eventType);
            result.put("code", "SUCCESS");
            result.put("message", "成功");
            return result;
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            log.error("【商户通知错误】商户号-> {}", wechatMerchantConfig.getMerchantName(), e);
            result.put("code", "FAIL");
            result.put("message", "签名验证失败");
            return result;
        } catch (BusinessException e) {
            e.printStackTrace();
            log.error("【商户通知错误】商户号-> {}", wechatMerchantConfig.getMerchantName(), e);
            result.put("code", "FAIL");
            result.put("message", "签名验证失败");
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("【商户通知错误】商户号-> {}", wechatMerchantConfig.getMerchantName(), e);
            result.put("code", "FAIL");
            result.put("message", "签名验证失败");
            return result;
        }
    }

    /**
     * 定时检测补偿是否有遗漏投诉
     * <p>
     * TODO 这个定时任务 有问题 待确认
     */
    public void handleNotifyJob() {
        log.info("开始执行定时检测补偿投诉是否遗漏");
        ZonedDateTime zonedDateTime = LocalDateTime.now().plusMinutes(-60).atZone(ZoneId.systemDefault());
        Date startDate = Date.from(zonedDateTime.toInstant());
        Date endDate = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
        Query query = new Query();
        query.addCriteria(Criteria.where("createdTime").gte(startDate).lte(endDate));
        List<ComplaintNotifyLog> logList = this.mongoTemplate.find(query, ComplaintNotifyLog.class);
        if (CollectionUtils.isEmpty(logList)) {
            return;
        }
        Map<String, Object> result = new HashMap<>(2);
        logList.stream().forEach(complaintNotifyLog -> {
            ComplaintNotify complaintNotify = complaintNotifyLog.getComplaintNotify();
            getNotifyResultMap(complaintNotifyLog.getTimestamp(), complaintNotifyLog.getNonce(), complaintNotifyLog.getSignature(),
                    complaintNotifyLog.getSerialNumber(),
                    result, null, complaintNotify);
        });
        log.info("结束执行定时检测补偿投诉是否遗漏");
    }

    public boolean delete(String id) {
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(id));
        Update update = new Update();
        update.set("deleted", true);
        update.set("updatedTime", new Date());
        return this.mongoTemplate.updateFirst(query, update, MerchantComplaint.class).
                getModifiedCount() > 0 ? true : false;
    }

    /**
     * 解密投诉人手机号
     *
     * @param merchantConfig
     * @param payerPhone
     * @return
     */
    private String decryptPhone(WechatMerchantConfig merchantConfig, String payerPhone) {
        if (StringUtils.isBlank(payerPhone)) {
            return "";
        }
        try {
            String decryptPhone = RsaCryptoUtil.decryptOAEP(payerPhone, getMerchantPrivateKey(merchantConfig.getPathPrivateKey()));
            return decryptPhone;
        } catch (BadPaddingException e) {
            e.printStackTrace();
            return "";
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    private String getRequestBody(HttpServletRequest request) {
        ServletInputStream inputStream = null;
        BufferedReader bufferedReader = null;
        try {
            inputStream = request.getInputStream();
            StringBuffer stringBuffer = new StringBuffer();
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream,
                    Charset.forName("UTF-8")));
            String s = null;
            //读取回调请求体
            while ((s = bufferedReader.readLine()) != null) {
                stringBuffer.append(s);
            }
            String s1 = stringBuffer.toString();
            return s1;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        } finally {
            if (Objects.nonNull(inputStream)) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (Objects.nonNull(bufferedReader)) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 商户号获取投诉
     *
     * @param wechatMerchantConfig
     * @param notifyDecrypt        通知解密内容
     * @param notifyType           投诉类型 COMPLAINT.CREATE：产生新投诉  COMPLAINT.STATE_CHANGE：投诉状态变化
     * @return
     */
    private void getRemoteComplaintDetail(WechatMerchantConfig wechatMerchantConfig, NotifyDecrypt notifyDecrypt, String notifyType) {
        String complaintId = notifyDecrypt.getComplaintId();
        if (StringUtils.isBlank(complaintId)) {
            log.error("【商户投诉】通知解密投诉通知为空 商户 - >{}", wechatMerchantConfig.getMerchantName());
            return;
        }
        WechatComplaintService wechatComplaintService = facotry.getWechatComplaintService(wechatMerchantConfig);
        MerchantComplaint merchantComplaintDetail = wechatComplaintService.queryDetail(complaintId);
        log.info("Complaint Detail merchantComplaintDetail:{}", merchantComplaintDetail);

        merchantComplaintDetail.setActionType(notifyDecrypt.getActionType());
        merchantComplaintDetail.setMerchantId(wechatMerchantConfig.getMerchantId());
        merchantComplaintDetail.setMerchantName(wechatMerchantConfig.getMerchantName());
        //解密用户手机号
        merchantComplaintDetail.setPayerPhone(decryptPhone(wechatMerchantConfig, merchantComplaintDetail.getPayerPhone()));
        //通知产生状态变更
        Query query = new Query();
        query.addCriteria(Criteria.where("complaintId").is(complaintId));
        MerchantComplaint merchantComplaint = this.mongoTemplate.findOne(query, MerchantComplaint.class);
        if (Objects.isNull(merchantComplaint)) {
            merchantComplaintDetail.setCreatedTime(new Date());
            merchantComplaintDetail.setId(null);
            log.error("【投诉-不存在】商户号-> 投诉ID - > {}", wechatMerchantConfig.getMerchantName(), complaintId);
            this.mongoTemplate.save(merchantComplaintDetail);
            return;
        }
        List<ReplyUserComplaint> replyUserComplaintList = merchantComplaint.getReplyUserComplaintList();
        if (CollectionUtils.isNotEmpty(replyUserComplaintList)) {
            merchantComplaintDetail.setReplyUserComplaintList(replyUserComplaintList);
        }
        merchantComplaintDetail.setId(merchantComplaint.getId());
        merchantComplaintDetail.setUpdatedTime(new Date());
        this.mongoTemplate.save(merchantComplaintDetail);
    }

    @Getter
    @Setter
    class ComplaintOrderDTO {
        private String activityName;
        private String status = "未退款";
        private String name;
        private String mobile;

    }


    private PrivateKey getMerchantPrivateKey(String pathPrivateKey) {
        try {
            File file = new File(pathPrivateKey);
            PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(file));
            return merchantPrivateKey;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw new BusinessException("未找到私钥文件路径");
        }
    }

    private String getRefundByOrderNo(String orderNo) {
        Query query = new Query();
        query.addCriteria(Criteria.where("orderNo").is(orderNo));
        query.addCriteria(Criteria.where("refundStatus").is("3"));
        OrderInfo orderInfo = this.mongoTemplate.findOne(query, OrderInfo.class);
        if (Objects.isNull(orderInfo)) {
            return "未退款";
        }
        if (Objects.nonNull(orderInfo.getRefundType()) && orderInfo.getRefundType() == 0) {
            return "全部退款";
        }
        if (Objects.nonNull(orderInfo.getRefundType()) && orderInfo.getRefundType() == 1) {
            return "部分退款";
        }
        return "全部退款";
    }

}
